
#pragma once

#include "operators.h"

//служат для генерации предупреждений от компилятора
//пример использования: #pragma message(__LOC__"ПРОВЕРИТЬ ФУНКЦИЮ DbImpl::ClientLogin")
// #define __STR2__(x) #x
// #define __STR1__(x) __STR2__(x)
// #define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: "

namespace tools
{
    
    template<class T = void , size_t N = wrapper_details::WrapperSizeStrategy<T>::eSIZE>struct Wrapper
        : wrapper_details::WrapperOperator<T, N>
    {
        //typedef WrapperBase<T,N>        Parent;
//        typedef typename Parent::Byte   Byte;

        Wrapper(): wrapper_details::WrapperOperator<T, N>() {}
        Wrapper(const Wrapper& src);
        Wrapper& operator=(const Wrapper& src);

        template<class U> Wrapper(const U& src);
        template<class U> Wrapper& operator=(const U& src);

        template<class U, size_t I> Wrapper(const Wrapper<U, I>& src);
        template<class U, size_t I> Wrapper& operator=(const Wrapper<U,I>& src);
    
        Wrapper Clone()const;
        template<class U, size_t I> void Clone(Wrapper<U,I>& dst)const;

        //сравнивает фактические типы ресурса и исходника
        template<class U>bool operator != (const U& src)const;
        template<class U>bool operator == (const U& src)const;
        template<class U, size_t I>bool operator != (const Wrapper<U,I>& src)const;
        template<class U, size_t I>bool operator == (const Wrapper<U,I>& src)const;

//         template<class U>friend ::std::basic_ostream<U>& operator<<(::std::basic_ostream<U>& os, const Wrapper& obj );
    };


//---------------------------------------------------------------------------------------------
    template<class T, size_t N>
        template<class U> Wrapper<T,N>::Wrapper(const U& src) 
        {
            operator = (src); 
        }

    template<class T, size_t N>
        template<class U> Wrapper<T,N>& Wrapper<T,N>::operator=(const U& src)
        {
            return this->PlaceNewObject(src), *this;
        }
//---------------------------------------------------------------------------------------------
    template<class T, size_t N>
        Wrapper<T,N>::Wrapper(const Wrapper& src){ operator=(src); }

    template<class T, size_t N>
        template<class U, size_t I> 
            Wrapper<T,N>::Wrapper(const Wrapper<U, I>& src){ operator=(src); }

    template<class T, size_t N>
        template<class U, size_t I> 
            Wrapper<T,N>& Wrapper<T,N>::operator=(const Wrapper<U,I>& src)
            {
                return src.Clone(*this), *this; 
            }

    template<class T, size_t N>
        Wrapper<T,N>& Wrapper<T,N>::operator=(const Wrapper& src)
        {
            return src.Clone(*this), *this;
        }
//---------------------------------------------------------------------------------------------
    template<class T, size_t N>
        Wrapper<T,N> Wrapper<T,N>::Clone()const { return Wrapper(*this); }
//---------------------------------------------------------------------------------------------
    template<class T, size_t N>
        template<class U, size_t I> void Wrapper<T,N>::Clone(Wrapper<U,I>& dst)const
        {
            static_assert(std::is_convertible<U*,T*>::value || ::std::is_same<T,void>::value, "TYPES ARE NOT CONVERTED");

            bool ERROR_INVALID_TYPE = !::std::is_same<U,T>::value && !this->template Is<U>();
            assert(!ERROR_INVALID_TYPE);
            if(ERROR_INVALID_TYPE)
                throw ::std::logic_error("ERROR_INVALID_TYPE");

            if(this->Empty())
                return dst.Clear();

            this->MyHelper().CloneMeIntoStack( dst.mData );

            dst.mAlloc = dst.GetSizeBufer() < this->MyHelper().GetSize();
            if( dst.mAlloc )
                dst.mPtr = (U*) this->CloneObjectIntoHeap();
            else
                dst.mPtr = (U*) this->CloneObjectIntoStack(dst.mData);
        }

//---------------------------------------------------------------------------------------------
    template<class T, size_t N>
        template<class U>bool Wrapper<T,N>::operator != (const U& src)const{ return !operator==(src); }

    template<class T, size_t N>
        template<class U>bool Wrapper<T,N>::operator == (const U& src)const
        {
            (void)src;
            return this->Empty()? false: typeid(*this->mPtr) == typeid(src);
        }
//---------------------------------------------------------------------------------------------
    template<class T, size_t N>
        template<class U, size_t I>
            bool Wrapper<T,N>::operator != (const Wrapper<U,I>& src)const{ return !operator==(src); }

    template<class T, size_t N>
        template<class U, size_t I>
            bool Wrapper<T,N>::operator == (const Wrapper<U,I>& src)const
            {
                const char v1 = this->Empty()?     1: 0;
                const char v2 = src.Empty()? 1: 0;

                return ( v1+v2 == 2 )? true:
                            (v1+v2==1) ? false:
                                typeid(*this->mPtr) == typeid(*src.mPtr);
            }

//---------------------------------------------------------------------------------------------
//     template<class U, class T, size_t N>
//         ::std::basic_ostream<U>& operator<<(::std::basic_ostream<U>& os, const Wrapper<T,N>& obj )
//         {
//             #pragma message(__LOC__"РЕАЛИЗОВАТЬ operator<< для Wrapper")
//             (void)obj;
//             return os;
//         }

//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------


}//namespace tools

